<?php

namespace app\modules\admin\models;

use Yii;
use yii\base\Exception;
use yii\base\Model;
use yii\helpers\Json;
use yii\rbac\Item;
use yii\rbac\Rule;

/**
 *
 * @property string $name
 * @property integer $type
 * @property string $description
 * @property string $ruleName
 * @property string $data
 * @property bool isNewRecord
 * @property Item $item
 * @property Item[] $items
 */
class AuthItem extends Model
{
	public $name;
	public $type;
	public $description;
	public $ruleName;
	public $data;

	/* @var Item */
	private $_item = null;

	/**
	 * 初始化对象
	 * @param Item $item
	 * @param array $config
	 */
	public function __construct($item = null, $config = [])
	{
		$this->_item = $item;
		if($item !== null) {
			$this->name = $item->name;
			$this->type = $item->type;
			$this->description = $item->description;
			$this->ruleName = $item->ruleName;
			$this->data = $item->data === null ? null : Json::encode($item->data);
		}
		parent::__construct($config);
	}

	public function rules() {
		return [
			[['ruleName'], 'checkRule'],
			[['name', 'type'], 'required'],
			[['name'], 'unique', 'when' => function() {
				return $this->isNewRecord || ($this->_item->name != $this->name);
			}],
			[['type'], 'integer'],
			[['description', 'data', 'ruleName'], 'default'],
			[['name'], 'string', 'max'=>64]
		];
	}

	public function attributeLabels()
	{
		return [
			'name' => '名称',
			'type' => '类型',
			'description' => '描述',
			'ruleName' => '规则名称',
			'data' => '数据'
		];
	}

	public function unique() {
		$mgr = Yii::$app->authManager;
		$value = $this->name;
		if($mgr->getRole($value) !== null || $mgr->getPermission($value) !== null) {
			$message = $this->getAttributeLabel('name') . ' "{value}" 已经存在了。';
			$params = ['value' => $value];
			$this->addError('name', Yii::$app->i18n->format($message,$params, Yii::$app->language));
		}
	}

	/**
	 * 检查规则是否有效
	 * @param $attribute
	 */
	public function checkRule($attribute) {
		$name = $this->ruleName;
		if (!Yii::$app->authManager->getRule($name)) {
			try {
				$rule = Yii::createObject($name);
				if($rule instanceof Rule) {
					$rule->name = $name;
					Yii::$app->authManager->add($rule);
				} else {
					$this->addError($attribute, '规则名称 {value} 错误');
				}
			} catch (\Exception $exception) {
				$this->addError($attribute, '规则 {value} 不存在！');
			}
		}
	}

	/**
	 * 获取所有
	 */
	public function getItems() {
		$mgr = Yii::$app->authManager;
		$available = [];
		if($this->type === Item::TYPE_ROLE) {
			foreach (array_keys($mgr->getRoles()) as $role) {
				$available[$role] = 'role';
			}
		}
		foreach (array_keys($mgr->getPermissions()) as $permission) {
			$available[$permission] = $permission[0] == '/' ? 'route' : 'permission';
		}

		$assigned = [];
		foreach ($mgr->getChildren($this->_item->name) as $item) {
			$assigned[$item->name] = $item->type == Item::TYPE_ROLE ? 'role' : ($item->name[0] == '/' ? 'route' : 'permission');
			unset($available[$item->name]);
		}
		unset($available[$this->name]);

		return [
			'available' => $available,
			'assigned' => $assigned
		];

	}

	public function getItem() {
		return $this->_item;
	}

	public function getIsNewRecord()
	{
		return $this->_item === null;
	}

	/**
	 * 查找角色
	 * @param string $name 角色名称
	 * @return AuthItem|null
	 */
	public static function find($name)
	{
		$item = Yii::$app->authManager->getRole($name);
		if($item !== null) {
			return new self($item);
		}
		return null;
	}

	public function save()
	{
		if($this->validate()) {
			$oldName = '';
			$mgr = Yii::$app->authManager;
			$isNew = $this->isNewRecord;
			if($isNew) {
				$this->_item = $this->type === Item::TYPE_ROLE ?
					$mgr->createRole($this->name) : $mgr->createPermission($this->name);
			} else {
				$oldName = $this->_item->name;
			}
			$this->_item->name = $this->name;
			$this->_item->description = $this->description;
			$this->_item->ruleName = $this->ruleName;
			$this->_item->data = empty($this->data) ? null : Json::encode($this->data);
			if($isNew) {
				$mgr->add($this->_item);
			} else {
				$mgr->update($oldName, $this->_item);
			}
			return true;
		}
		$tmp = $this->getErrors();
		return false;
	}

	public function addChildren($items) {
		$mgr = Yii::$app->authManager;
		$success = 0;
		if($this->_item !== null) {
			foreach ($items as $item) {
				$child = $this->type === Item::TYPE_ROLE ? $mgr->getRole($item) : $mgr->getPermission($item);
				try {
					$mgr->addChild($this->_item, $child);
					$success++;
				} catch (Exception $exception) {
					Yii::error($exception->getMessage(), __METHOD__);
				}
			}
		}
		return $success;
	}

	public function removeChildren($items) {
		$mgr = Yii::$app->authManager;
		$success = 0;
		if ($this->_item !== null) {
			foreach ($items as $item) {
				$child = $this->type === Item::TYPE_ROLE ? $mgr->getRole($item) : $mgr->getPermission($item);
				try {
					$mgr->removeChild($this->_item, $child);
					$success++;
				} catch (Exception $exception) {
					Yii::error($exception->getMessage(), __METHOD__);
				}
			}
		}
		return $success;
	}
}
